#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "cJSON.h"
#include "easyjs.h"
#include "ktota.h"

#define FileName "ktota_cfg.json"
#define JS_MAX_SIZE (10*1024)

#define DEFUALT_BOARD_MODEL  0x10106003 /* 101-06-003*/
#define DEFUALT_SOFT_VERSION 0x30101 /* 301.01 = v3.01.01 */

/* 默认值 */
struct _usercfg usercfg = {\
{"/dev/ttyS0"}, \
{"update.bin"}, \
115200,\
DEFUALT_BOARD_MODEL,\
DEFUALT_SOFT_VERSION,\
};

int parse_numb(cJSON *f, char *item, uint32_t *val);
int parse_str(cJSON *f, char *item, char* val);
#define GET_NUM32(ITEM, p) parse_numb(root, ITEM, (uint32_t*)p)
#define GET_STR(ITEM, p) parse_str(root, ITEM, (char*)p)

int unserialize_numb_double(cJSON *f, char *item, double *val) {
    int ret = 0; 
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            *val = cJSON_GetNumberValue(s);
            ret = 1;
        }
    }
    return ret;
}

int parse_numb(cJSON *f, char *item, uint32_t *val) {
    int ret = 0; 
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            double number = cJSON_GetNumberValue(s);
            *val = (uint32_t)number;
            ret = 1;
        }
    }
    return ret;
}

int parse_str(cJSON *f, char *item, char* val) {
    int ret = 0; 
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            char* src = cJSON_GetStringValue(s);
            if( NULL != strcpy(val, src)) {
                ret = 1;
            }
        }
    }
    return ret;
}

static int unserialize(char *text)
{
    cJSON *root = cJSON_Parse(text);
	if (!root) {
        printf("cJSON unserialize failed\n");
        return -1;
    }else {
        GET_STR("uart_name", &usercfg.uart_name);
        GET_STR("file_name", &usercfg.file_name);
        GET_NUM32("uart_baud", &usercfg.uart_baud);
        GET_NUM32("bin_maigc", &usercfg.bin_maigc);
        GET_NUM32("bin_ver", &usercfg.bin_ver);
	}
    printf("uart_name: %s baud: %d\r\n", usercfg.uart_name, usercfg.uart_baud);
    printf("cfg bin file: %s magic: %08X version: %x.%02x\r\n", usercfg.file_name,\
         usercfg.bin_maigc, usercfg.bin_ver >> 8, usercfg.bin_ver&0xff);
    cJSON_Delete(root);
    return 0;
}

static int unserialize_file(const char* file_name)
{
    int ret = 0;
	FILE *f; long len; char *data;
	f = fopen(file_name, "rb");
    if(f == NULL) {
        return -1;
    }
	fseek(f, 0, SEEK_END);
	len = ftell(f);
    if(len <= 0) {
        return -2;
    }
	fseek(f, 0, SEEK_SET);
	data = (char*)malloc(len + 1);
	fread(data, 1, len, f);
	fclose(f);
	ret = unserialize(data);
	free(data);
    return ret;
}

static int _json_save(cJSON *root) { 
    char *out = malloc(JS_MAX_SIZE);
    if (!cJSON_PrintPreallocated(root, out, JS_MAX_SIZE, 1)) {
        printf("cJSON Print failed!\n");
        return -1;
    }
    FILE* fp = fopen(FileName ,"w+"); 	
	fprintf(fp, "%s", out);
	fclose(fp);
    free(out);
    return 0;
}

static void _cfg_restore(void)
{
    cJSON *root = cJSON_CreateObject();
    if(root) {
        cJSON_AddStringToObject(root, "uart_name", usercfg.uart_name);
        cJSON_AddStringToObject(root, "file_name", usercfg.file_name);
        cJSON_AddNumberToObject(root, "uart_baud", usercfg.uart_baud);
        cJSON_AddNumberToObject(root, "bin_maigc", usercfg.bin_maigc);
        cJSON_AddNumberToObject(root, "bin_ver", usercfg.bin_ver);
        _json_save(root); 
    }
}



void CJSON_CDECL json_cfg_init(void) {
    if( unserialize_file(FileName) ) {
        _cfg_restore();
    }
}


